﻿/*
 * source comes from http://www.jonathanantoine.com/2011/09/23/wpf-4-5s-markupextension-invoke-a-method-on-the-viewmodel-datacontext-when-an-event-is-raised/
 * */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Markup;

namespace Mammoth.Libs
{
    public class Call : MarkupExtension
    {
        public string ActionName { get; set; }

        public Call(string actionName) { ActionName = actionName; }
        public Call() { }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            IProvideValueTarget targetProvider = serviceProvider
                .GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
            if (targetProvider == null)
                throw new InvalidOperationException(@"The CallAction extension can't retrieved the IProvideValueTarget service.");

            Type delegateType = null;

            var targetMethodInfo = targetProvider.TargetProperty as MethodInfo;
            if (targetMethodInfo != null)
            {
                ParameterInfo[] pars = targetMethodInfo.GetParameters();
                delegateType = pars[1].ParameterType;
            }

            var targetEventInfo = targetProvider.TargetProperty as EventInfo;
            if (targetEventInfo != null)
            {
                delegateType = targetEventInfo.EventHandlerType;
            }

            //Retrieves the method info of the proxy handler
            MethodInfo methodInfo = this.GetType().GetMethod("MyProxyHandler",
                BindingFlags.NonPublic | BindingFlags.Instance);

            //Create a delegate to the proxy handler on the markupExtension
            Delegate returnedDelegate =
                Delegate.CreateDelegate(delegateType, this, methodInfo);
            return returnedDelegate;

        }

        void MyProxyHandler(object sender, EventArgs e)
        {
            FrameworkElement target = sender as FrameworkElement;
            if (target == null) return;
            var dataContext = target.DataContext;
            if (dataContext == null) return;

            //get the method on the datacontext from its name
            MethodInfo methodInfo = dataContext.GetType()
                .GetMethod(ActionName, BindingFlags.Public | BindingFlags.Instance);
            var pars = methodInfo.GetParameters();
            if (pars.Count() == 0)
                methodInfo.Invoke(dataContext, null);
            else
                methodInfo.Invoke(dataContext, new object[2] { sender, e });
        }
    }
}
